/**
 * Copyright ©2016-2020 northkingbpo Corporation, All Rights Reserved
 * http://www.northkingbpo.net/
 */
package profile.hujia.algorithm.parallel;

import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import static profile.hujia.algorithm.common.ParticleSwarmOptimizationFunction.adjustFeasibleSolution;
import static profile.hujia.algorithm.common.ParticleSwarmOptimizationFunction.getScore;
import static profile.hujia.algorithm.iteration.ParticleSwarmOptimizationModeOne.*;

/**
 * class info
 *
 * @author hujia
 * @date 2019-01-28 17:09
 */
@Slf4j
public class ParticleSwarmOptimizationModeOneMove implements Runnable {

    private double random1;
    private double random2;
    private int begin;
    private int end;
    private double[][] velocitySwarm;
    private int[][] feasibleSolutionSwarm;
    private int[][] constraintCondition;
    private int[][] particleBestSolution;
    private int[] globalBestSolution;
    private int[] particleBestSolutionScore;
    private Map<String, Integer> score;
    private Map<Integer, Integer> constraintUser = new HashMap<>();
    private CountDownLatch countDownLatch;
    private int taskNumber;

    public ParticleSwarmOptimizationModeOneMove(int taskNumber, double random1, double random2, int begin, int end,
                                                double[][] velocitySwarm, int[][] feasibleSolutionSwarm,
                                                int[][] constraintCondition, int[][] particleBestSolution,
                                                int[] globalBestSolution, int[] particleBestSolutionScore,
                                                Map<String, Integer> score, CountDownLatch countDownLatch) {
        this.taskNumber = taskNumber;
        this.random1 = random1;
        this.random2 = random2;
        this.begin = begin;
        this.end = end;
        this.velocitySwarm = velocitySwarm;
        this.feasibleSolutionSwarm = feasibleSolutionSwarm;
        this.constraintCondition = constraintCondition;
        this.globalBestSolution = globalBestSolution;
        this.particleBestSolution = particleBestSolution;
        this.particleBestSolutionScore = particleBestSolutionScore;
        this.score = score;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        for (int i = begin; i < end; ++i) {
            for (int j = 0; j < taskNumber; ++j) {
                try {
                    velocitySwarm[i][j] = W_MAX * velocitySwarm[i][j] +
                            C_1 * random1 * (particleBestSolution[i][j] - feasibleSolutionSwarm[i][j]) +
                            C_2 * random2 * (globalBestSolution[j] - feasibleSolutionSwarm[i][j]);
                    feasibleSolutionSwarm[i][j] += adjustVelocity(velocitySwarm[i][j]);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
            adjustFeasibleSolution(feasibleSolutionSwarm[i], constraintUser, constraintCondition,taskNumber);
            int currentScore = getScore(feasibleSolutionSwarm[i], constraintCondition, score,taskNumber);
            if (particleBestSolutionScore[i] < currentScore) {
                particleBestSolutionScore[i] = currentScore;
                particleBestSolution[i] = feasibleSolutionSwarm[i].clone();
            }
        }
        countDownLatch.countDown();
    }

    private int adjustVelocity(double velocityBranch) {
        if (velocityBranch > 0.5) {
            return 1;
        } else if (velocityBranch > -0.5 && velocityBranch <= 0.5) {
            return 0;
        } else {
            return -1;
        }
    }

}
